﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace YunHao
{
    /// <summary>
    /// 管理所有自定义携程（单例模式）
    /// </summary>
    public class CoroutineManager : MonoBehaviour
    {

        public static CoroutineManager Instance
        {
            get
            {
                if (!instance)
                    instance = new GameObject("CoroutineManager", typeof(CoroutineManager)).GetComponent<CoroutineManager>();
                return instance;
            }
        }

        private static CoroutineManager instance;

        void Awake()
        {
            if (!instance)
                instance = this;
            InitCoroutineControl();
        }

        void Update()
        {
            MonitorCoroutineControl();
        }

        void OnDestroy()
        {
            ReleaseCoroutineControl();
        }

        #region 携程分组管理

        /// <summary>
        /// 普通携程缓存
        /// </summary>
        private List<Group> _groups = new List<Group>();

        /// <summary>
        /// 没有指定分组时的使用该命名分组
        /// </summary>
        private string _emptyGroupName;

        /// <summary>
        /// 初始化携程控制
        /// </summary>
        void InitCoroutineControl()
        {
            //确保空分组唯一性
            _emptyGroupName = System.Guid.NewGuid().ToString();
        }

        /// <summary>
        /// 监控携程控制
        /// </summary>
        void MonitorCoroutineControl()
        {
            //清除空的group
            int length = _groups.Count;
            for (int i = 0; i < length; i++)
            {
                if (_groups[i].CoroutineCount == 0)
                {
                    _groups.RemoveAt(i);
                    i--;
                    length--;
                }
            }
        }

        /// <summary>
        /// 释放携程
        /// </summary>
        void ReleaseCoroutineControl()
        {
            foreach (Group mc in _groups)
            {
                mc.Stop();
            }
            _groups.Clear();
            _groups = null;
        }

        /// <summary>
        /// 创建携程
        /// </summary>
        /// <param name="e">携程</param>
        /// <param name="groupName">分组</param>
        /// <param name="autoStart">是否自动启动</param>
        /// <param name="onStart">启动事件</param>
        /// <param name="onFinished">结束事件</param>
        /// <returns></returns>
        public InterruptCoroutine CreateCoroutine(IEnumerator e, string groupName, bool autoStart = true, Action onStart = null, Action<bool> onFinished = null)
        {
            var group = CreateGroup(groupName);
            return group.CreateCoroutine(this, e, autoStart, onStart, onFinished);
        }

        /// <summary>
        /// 停止携程组
        /// </summary>
        /// <param name="groupName"></param>
        public void StopGroup(string groupName)
        {
            if (string.IsNullOrEmpty(groupName)) return;
            Group group = null;
            foreach (Group gp in _groups)
            {
                if (gp.key == groupName)
                {
                    group = gp;
                    break;
                }
            }
            if (null != group)
            {
                group.Stop();
                _groups.Remove(group);
            }
        }

        /// <summary>
        /// 创建携程组
        /// </summary>
        /// <param name="groupName"></param>
        /// <returns></returns>
        Group CreateGroup(string groupName)
        {
            Group group = null;
            foreach (Group gp in _groups)
            {
                if (gp.key == groupName)
                {
                    group = gp;
                    break;
                }
            }
            if (null == group)
            {
                if (string.IsNullOrEmpty(groupName))
                    groupName = _emptyGroupName;
                group = new Group(groupName);
            }
            return group;
        }

        /// <summary>
        /// 携程组
        /// </summary>
        public class Group
        {
            /// <summary>
            /// 标识
            /// </summary>
            public string key;
            /// <summary>
            /// 携程数量
            /// </summary>
            public int CoroutineCount
            {
                get
                {
                    return _coroutines.Count;
                }
            }
            /// <summary>
            /// 缓存携程
            /// </summary>
            private List<InterruptCoroutine> _coroutines;

            public Group(string key)
            {
                this.key = key;
                _coroutines = new List<InterruptCoroutine>();
            }

            ~Group()
            {
                Stop();
                _coroutines.Clear();
                _coroutines = null;
            }

            /// <summary>
            /// 在组中创建一个携程
            /// </summary>
            /// <param name="mono"></param>
            /// <param name="e"></param>
            /// <param name="autoStart"></param>
            /// <param name="onStart"></param>
            /// <param name="onFinished"></param>
            /// <returns></returns>
            public InterruptCoroutine CreateCoroutine(MonoBehaviour mono, IEnumerator e, bool autoStart = true, Action onStart = null, Action<bool> onFinished = null)
            {
                InterruptCoroutine mineCoroutine = new InterruptCoroutine(e, mono);
                mineCoroutine.OnStart += onStart;
                mineCoroutine.OnFinished += onFinished;
                if (autoStart)
                    mineCoroutine.Start();
                _coroutines.Add(mineCoroutine);
                mineCoroutine.OnFinished += (manual) =>
                {
                    _coroutines.Remove(mineCoroutine);
                };
                return mineCoroutine;
            }

            /// <summary>
            /// 停止组中携程
            /// </summary>
            public void Stop()
            {
                foreach (InterruptCoroutine ic in _coroutines)
                {
                    if (null != ic) ic.Stop();
                }
            }
        }

        #endregion
    }
}
